Amateur Reverse Engineering
Last month, in an unfortunate series of events, I decided to update my favorite calorie tracking app, after a year.
What followed was a week of chaotic tech escapades.
Fear the AI-fication
After updating the app, much to my disappointment, the app was AI-fied and bent out of shape. The one-click calorie tracking feature now took me 3 clicks. And cherry on the top, the offline calorie tracker feature was removed.
While there are lots of open-source calorie tracking apps available on F-droid, none of them have a reliable database for Indian foods.
So I decided to take matters into my own hands and what followed next was inevitable!
Data is the new oil
I decided to get/scrape/dig up all the calorie data from the app itself, and make an app out of calorie tracking. And since it was proprietary data, I knew it wasn’t going to be easy.
Still I dared to hope and tried the easier way first.
The easy way: In older versions, this app had an offline database and the data was downloaded on first setup. So I suspected that there must be a SQLite file somewhere on my phone responsible for it.
Since Android doesn’t show the system app data without root. Quickly, I set up an Android emulator, rooted it, installed a Root File explorer along with Shizuku, and started looking for calorie db in Android system files. It took quite a few retries, and at the end, I found a likely culprit, an 8MB SQLite file. Tried to open it in terminal via SQLite tool. And Bam! It couldn’t be read. Well, I wasn’t inclined to spend more time decrypting it. I dropped the idea and moved to the hard way.
The hard way: In that emulator, I installed HTTP Toolkit. (which installs a custom certificate and allows you to inspect traffic from URLs, basically Wireshark for Android). After inspecting traffic for a while, I identified the culprit API responsible for fetching food data. It looked something like this:
https://api.xyz.com/api/v3/food/details?food_id=<food_id>
This returned Calorie, micro and macro nutrients data of that particular food_id as below:
{
"food": {
"food_id": 16349,
"food_name": "Cinnamon Vinegar Lemon Honey Water",
"food_rrr_score": 0.46897858934694503,
},
"food_measures": [
{
"measure_name": "cup",
"calorie": 36.07447,
"carbs": 8.97298, "fats": 0.01917, "fibre": 0.36849, "proteins": 0.07263
"common_measure_name": "cup", "default_quantity": 1, "food_id": 16349, "food_type": null, "id": 56099, "measure_id": 56099, "measure_volume": 250, "measure_weight": 250, "metric_unit": "grams",
"micronutrient_details": {
"calcium": 8.02344, "cholestrol": 0, "iron": 0.08433, "magnesium": 3.03118, "saturated_fats": 0.00194, "sodium": 9.53419, "total_sugars": 8.22535, "vitamin_a": 0.29053, "vitamin_c": 1.87391, "zinc": 0.04968
},
},
{
"measure_name": "ml",
"calorie": 0.1443,
.......
"proteins": 0.00859
}
]
}
In the app, the micronutrient data was a paywalled feature, but via API it could be accessed for free. Was I crossing into piracy land already?
After that, I fiddled around with query parameters but couldn’t find a way to fetch data in bulk. The range of food was from 1 to around 2,50,000. The only option was to scrape the data, one query at a time. Sigh! This was gonna take weeks.
Rate limiting has always been the nemesis of scrapers.
And, a health company with 1 Crore+ downloads would definitely have implemented a server-side rate limiting, right?
Nope.
Rate Limiting 101
They didn’t had any rate-limiting at all. Data Democracy for all.
It took me two days, a Python script and an infinite amount of patience to scrape all the data.
It didn’t made me feel smug though, since the first thing I drew in HLD interviews is a rate limiter. And even after being such a popular app, they didn’t implement it. Must be running on those free 1Million AWS credits, like one of my friend’s startups.
Oil is here, now what?
After that, I converted all that json data into a nice 250MB SQLite db. Data was split into three tables- for faster searching and indexing.
Now, I decided to make an Android app for Calorie tracking using that SQLite data. I was a little familiar with Flutter, so I decided to revise the basics first.
I researched for the best resources. Downloaded tutorials. Set up my local environment. I was stoked and on a roll. I finished the official flutter tutorial, made that minimal app. I started coding the calorie app all by myself.
And….
Vibe…. What?
The difference between the UI I wanted and the UI I could make was too much.
As much as I didn't want to vibe code this project (After reading dozens of anti-AI and skill-atrophy articles), I gave in. I wrote a markdown document with all the specifications, data format, APIs, and gave it to Claude. Compiled the output, gave it to Claude again… You know the drill.
Wait, after I ran out of their free tier limits, I used Gemini. Thanks Google.
I had to make some code modifications, but at the end, the app was ready and it looked glorious.
Wait, it’s Calorie Searching, not Calorie Tracking!
Hard times create strong apps , good times create weak apps !
And now that I was feeling euphoric after building out the initial version, as is the rule of universe, progress was going to stall. The motivation was going to dry up.
So I did the next best possible thing, dropped the app-calorie-tracking-idea altogether, started vibe-tracking calories in my head and waited for the motivation to strike.
The motivation, like a freelancer’s income, arrived after a few days. And when I thought of acting on it, it was too late.
It so happened that I had to format my laptop in between. The most cherished local flutter development setup was gone. While I still had the code, setting things up, and fiddling again with the project, seemed like a daunting task.
In addition to that I figured that thinking of designing a lovely app is much easier than making it, even though the first one gave more dopamine hits.
So, just like my friend’s cat, I moved on to the next shiny thing, thinking of what ground-breaking stuff to make.